#ifndef __GAME_MANAGER_H__
#define __GAME_MANAGER_H__

#include <entt/entt.hpp>
#include <vector>
#include "Subsystems/Subsystem.hpp"
#include "BS_thread_pool.hpp"
#include "nlohmann/json.hpp"
#include <mutex>
#include <typeinfo>
#include <set>
#include "Utils/Hash.hpp"

#include "GameSingleton.h"

namespace PocketSurvival
{
    class GameManager : public SimpleSingletonItem
    {
        friend class SimpleSingleton;
    private:
        GameManager();
        ~GameManager();
        GameManager(const GameManager &) = delete;
        GameManager(GameManager &&) = delete;
        GameManager &operator=(const GameManager &) = delete;
        GameManager &operator=(GameManager &&) = delete;

    public:
        constexpr inline const std::string& getNowWorldPath() noexcept;
        constexpr inline const std::string& getNowWorldPlayersPath() noexcept;
        constexpr inline const std::string& getNowWorldMapsPath() noexcept;
        void update(float dt);
        void loadGame();
        void saveGame();
        void saveGameToMsgJson(nlohmann::json &jsonData);

        ///////////////////////////////////////////////
        // 以下方法只能在 initialize 或者 load 的时候才能使用
        ///////////////////////////////////////////////

        template<class T>
        constexpr inline T* registerSubsystem()
        {
            size_t hashCode = Utils::Hash::GetTypeHash<T>();
            T *t = GameSingleton::singletonPtr->registerSingleton<T>();
            subsystemMap[hashCode] = t;
            return t;
        }

        template<class T, class T2>
        constexpr inline T2* replaceSubsystem()
        {
            size_t hashCode = Utils::Hash::GetTypeHash<T>();
            T2 *t2 = GameSingleton::singletonPtr->replaceOrRegister<T, T2>();
            subsystemMap[hashCode] = t2;
            return t2;
        }

              
        template<class T, class T2>
        constexpr inline T2* replaceSubsystemNotDelete()
        {
            size_t hashCode = Utils::Hash::GetTypeHash<T>();
            T2 *t2 = GameSingleton::singletonPtr->replaceNotDelete<T, T2>();
            subsystemMap[hashCode] = t2;
            return t2;
        }


    public:
        std::map<size_t ,Subsystem *> subsystemMap;

    private:
        std::string m_nowWorldPath;
        std::string m_nowWorldPlayersPath;
        std::string m_nowWorldMapsPath;

        std::set<Subsystem *> m_singleUpdateSubsystemSet;
        std::set<Subsystem *> m_threadUpdateSubsystemSet;
    };

    constexpr inline const std::string& GameManager::getNowWorldPath() noexcept
    {
        return m_nowWorldPath;
    }
    constexpr inline const std::string& GameManager::getNowWorldPlayersPath() noexcept
    {
        return m_nowWorldPlayersPath;
    }
    constexpr inline const std::string& GameManager::getNowWorldMapsPath() noexcept
    {
        return m_nowWorldMapsPath;
    }
}

#endif